import pygame


def load_image(path):
    try:
        image = pygame.image.load(path)
    except pygame.error as e:
        print("Cannot load image:", path)
        raise SystemExit(e)
    image = image.convert_alpha()
    return image, image.get_rect()


def load_sound(path):
    class NoneSound:
        def play(self): pass
    if not pygame.mixer:
        return NoneSound()
    try:
        sound = pygame.mixer.Sound(path)
    except pygame.error as e:
        print("Cannot load sound:", path)
        raise SystemExit(e)
    return sound


class Fist(pygame.sprite.Sprite):
    image: pygame.Surface
    rect: pygame.Rect
    punching: bool

    def __init__(self):
        super().__init__()
        self.image, self.rect = load_image("chimp/fist.png")
        self.punching = False

    def update(self):
        pos = pygame.mouse.get_pos()
        self.rect.midtop = pos
        if self.punching:
            self.rect.move_ip(5, 10)

    def punch(self, target):
        if not self.punching:
            self.punching = True
            hitbox = self.rect.inflate(-5, -5)
            return hitbox.colliderect(target.rect)

    def unpunch(self):
        self.punching = False


class Chimp(pygame.sprite.Sprite):
    image: pygame.Surface
    rect: pygame.Rect
    area: pygame.Rect

    def __init__(self):
        super().__init__()
        self.image, self.rect = load_image('chimp/chimp.png')
        self.area = pygame.display.get_surface().get_rect()
        self.rect.topleft = 10, 10
        self.move = 9
        self.dizzy = 0
        self.original = None

    def update(self):
        """walk or spin, depending on the monkeys state"""
        if self.dizzy:
            self._spin()
        else:
            self._walk()

    def _walk(self):
        """move the monkey across the screen, and turn at the ends"""
        newpos = self.rect.move((self.move, 0))
        if not self.area.contains(newpos):
            if self.rect.left < self.area.left or \
                    self.rect.right > self.area.right:
                self.move = -self.move
                newpos = self.rect.move((self.move, 0))
                self.image = pygame.transform.flip(self.image, 1, 0)
            self.rect = newpos

    def _spin(self):
        """spin the monkey image"""
        center = self.rect.center
        self.dizzy += 20
        if self.dizzy >= 360:
            self.dizzy = 0
            self.image = self.original
        else:
            rotate = pygame.transform.rotate
            self.image = rotate(self.original, self.dizzy)
        self.rect = self.image.get_rect(center=center)

    def punched(self):
        """this will cause the monkey to start spinning"""
        if not self.dizzy:
            self.dizzy = 1
            self.original = self.image


def main():
    pygame.init()
    screen = pygame.display.set_mode((468, 80))  # type: pygame.Surface
    pygame.display.set_caption("Monkey Fever")
    pygame.mouse.set_visible(False)

    bg = pygame.Surface(screen.get_size())
    bg = bg.convert()
    bg.fill((250, 250, 250))

    if pygame.font:
        font = pygame.font.Font(None, 23)
        text = font.render("Pummel The Chimp, And Win $$$", 1, (10, 10, 10))
        textpos = text.get_rect(centerx=bg.get_width() / 2)
        bg.blit(text, textpos)

    screen.blit(bg, (0, 0))
    fist = Fist()
    chimp = Chimp()
    whiff_sound = load_sound('chimp/whiff.wav')
    punch_sound = load_sound('chimp/punch.wav')
    all_sprites = pygame.sprite.Group((fist, chimp))

    clock = pygame.time.Clock()
    while True:
        clock.tick(30)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return
            elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
                return
            elif event.type == pygame.MOUSEBUTTONDOWN:
                if fist.punch(chimp):
                    punch_sound.play()
                    chimp.punched()
                else:
                    whiff_sound.play()
            elif event.type == pygame.MOUSEBUTTONUP:
                fist.unpunch()

        screen.blit(bg, (0, 0))
        all_sprites.update()
        all_sprites.draw(screen)
        pygame.display.update(all_sprites.sprites())


if __name__ == "__main__":
    main()